/*
 * @(#)Security.java	1.59 01/12/12
 *
 * 版权所有2002太阳微系统公司。保留所有权利。SUN专有/机密。使用受许可条款的约束。
 */
 
package java.security;

import java.util.*;
import java.io.*;
/**
 * <p>此类集中了所有安全属性和常见安全方法。它的主要用途之一是管理提供商。
 *
 * @version 1.54 97/02/06
 * @author Benjamin Renaud */
public final class Security {

    /* Are we debugging? -- for developers */
    static boolean debug = false;

    /* Are we displaying errors? -- for users */
    static boolean error = true;

    /* The java.security properties */
    private static Properties props; 

    /* Where we cache provider properties */
    private static Properties propCache;

    /* A vector of providers, in order of priority */
    private static Vector providers;

    static {
	initialize();
    }
    
    private static void initialize() {
	props = new Properties();
	propCache = new Properties();
	providers = new Vector();

	File propFile = securityPropFile("java.security");
	if (!propFile.exists()) {
	    System.err.println("security properties not found. using defaults.");
	    initializeStatic();
	} else {
	    try {
		FileInputStream fis = new FileInputStream(propFile);
		InputStream is = new BufferedInputStream(fis);
		props.load(is);
		is.close();
	    } catch (IOException e) {
		error("could not load security properties file from " + propFile +
		      ". using defaults.");
		initializeStatic();
	    }
	}
	loadProviders();
    }

    /* 
     * Initialize to default values, if <java.home>/lib/java.security
     * is not found.
     */
    private static void initializeStatic() {
	props.put("security.provider.1", "sun.security.provider.Sun");
	props.put("system.scope","sun.security.provider.IdentityDatabase");
    }

    /**
     * Don't let anyone instantiate this. 
     */
    private Security() {
    }

    /**
     * 通过提供商声明循环，其形式预计为：
     *
     * security.provider.1=sun.security.provider.Sun
     * security.provider.2=sun.security.jsafe.Jsafe
     * etc.
     *
     * 该顺序确定查找算法时的默认搜索顺序。
     */
    private static void loadProviders() {

	int i = 1;

	while(true) {

	    String name = props.getProperty("security.provider." + i++);
	    if (name == null) {
		break;

	    } else {
		Provider prov = Provider.loadProvider(name);
		if (prov != null) {
		    /* 这必须直接操作数据结构，因为通过addProviders会导致安全检查发生，这有时会导致安全初始化失败，并产生不良后果。 */
		    providers.addElement(prov);
		}
	    }
	}
    }

    static File securityPropFile(String filename) {
	// maybe check for a system property which will specify where to
	// look. Someday.
	String sep = File.separator;
	return new File(System.getProperty("java.home") + sep + "lib" + sep + 
			"security" + sep + filename);
    }

    /**
     * 查找提供程序，并返回映射键的属性（如果有）。查找提供程序的顺序是安全属性文件中指定的提供程序首选项顺序。
     */
    static String getProviderProperty(String key) {
	
	String prop = propCache.getProperty(key);
	if (prop != null) {
	    return prop;
	}

	for (int i = 0; i < providers.size(); i++) {
	    Provider prov = (Provider)providers.elementAt(i);
	    
	    prop = prov.getProperty(key);
	    if (prop != null) {
		propCache.put(key, prop);
		return prop;
	    }
	}
	return prop;
    }

    /**
     * We always map names to standard names
     */
    static String getStandardName(String alias, String engineType) {
	return getProviderProperty("Alg.Alias." + engineType + "." + alias);
    }

    /** 
     * 获取算法的指定属性。算法名称应为标准名称。
	 * 有关标准算法名称的信息，请参阅<a href>Java加密体系结构API规范和参考</a>中的附录A。
	 * 一种可能的用途是专门的算法解析器，它可以将类映射到它们理解的算法(很像关键解析器所做的那样)。
     *
     * @param algName the algorithm name.
     *
     * @param propName the name of the property to get.
     * 
     * @return the value of the specified property.  
     */
    public static String getAlgorithmProperty(String algName,
					      String propName) {
	return getProviderProperty("Alg." + propName + "." + algName);
    }

    /** 
     * 给定算法名称，返回能够处理该算法密钥的PublicKey类的名称。算法名称应该是标准名称。
	 * 有关标准算法名称的信息，请参阅《<a href= "../guide/security/CryptoSpec.html#AppA">Java加密架构API规范参考》</a>中的附录A。
     *
     * @param algName the standard algorithm name for which to get
     * a public key class name.
     */
    static String getPublicKeyClassName(String algName, String format) {

	String stdName = getStandardName(algName, "Key");

	if (stdName == null) {
	    stdName = algName;
	}

	String formatAndAlg = "PublicKey." + format + "." + stdName;
	return getProviderProperty(formatAndAlg);
    }


    /**
	 * 给定算法名称，返回能够处理该算法密钥的PrivateKey类的名称。算法名称应该是标准名称。
	 * 请参阅《<a href=  "../guide/security/CryptoSpec.html#AppA">Java加密架构API规范参考》
	 * </a>中的附录A有关标准算法名称的信息。
     */
    static String getPrivateKeyClassName(String algName, String format) {

	String stdName = getStandardName(algName, "Key");

	if (stdName == null) {
	    stdName = algName;
	}

	return getProviderProperty("PrivateKey." + format + "." + stdName);
    }

    static String getEngineClassName(String algName,
				     String engineType)
    throws NoSuchAlgorithmException {
	/* First get the standard name */
	String stdName = getStandardName(algName, engineType);
	
	if (stdName == null) {
	    stdName = algName;
	}

	Class impl = null;

	Enumeration enum = providers.elements();

	String classname = getProviderProperty(engineType + "." + stdName);

	if (classname != null) {
	    return classname;
	}

	throw new NoSuchAlgorithmException("algorithm " + algName + 
					   " not available.");
    }

    /**
	 * 给定算法名称，返回能够处理该算法密钥的Signature类的名称。算法名称应该是标准名称。
	 * 有关标准算法名称的信息，请参阅《<a href= "../guide/security/CryptoSpec.html#AppA">Java加密架构API规范参考》</a>中的附录A。
     */
    private static String getEngineClassName(String algName, String provider, 
					     String engineType) 
    throws NoSuchAlgorithmException, NoSuchProviderException {

	if (provider == null) {
	    return getEngineClassName(algName, engineType);
	}

	/* First get the standard name */
	String stdName = getStandardName(algName, engineType);
	
	if (stdName == null) {
	    stdName = algName;
	}

	Provider prov = getProvider(provider);
	if (prov == null) {
	    throw new NoSuchProviderException("no such provider: " +
						provider);
	}
	
	String className = prov.getProperty(engineType + "." + stdName);
	if (className == null) {
	    throw new NoSuchAlgorithmException("no such algorithm: " +
						     algName + 
						     " for provider " +
						 provider);
	}
	return className;
    }

    /**
     * 在指定位置添加新提供程序。该位置是搜索提供商以查找请求的算法的首选顺序。
	 * 请注意，并不能保证此偏好会得到尊重。位置以1为基础，即1是最优先的，然后是2，等等。
	 * 有时添加提供者是合法的，但仅限于最后一个位置，在这种情况下，<code>位置</code>参数将被忽略。
     * 
     *  <p>如果给定的提供商安装在请求的位置，则曾经位于该位置的提供商以及位置大于<code>位置</code>
	 *  的所有提供商都会向上移动一个位置（朝向已安装提供商列表的末尾）。
     * 
     * <p>A provider cannot be added if it is already installed.
     *
     * @param provider the provider to be added.
     *
     * @param position the preference position that the caller would
     * like for this provider.
     *
     * @return 添加提供者的实际首选项位置，或者如果由于已安装而未添加提供者，则为-1。
     *
     * @see #getProvider
     * @see #removeProvider 
     */
    public static int insertProviderAt(Provider provider, int position) {

	check();

	/* First check if the provider is already installed */
	Provider already = getProvider(provider.getName());
	if (already != null) {
	    return -1;
	}	
		
	int size = providers.size();
	if (position > size || position <= 0) {
	    position = size+1;
	}

	providers.insertElementAt(provider, position-1);

	/* clear the prop caches */
	propCache = new Properties();
	
	return position;
    }

    /**
     * Adds a provider to the next position available.
     *
     * @param provider the provider to be added.
     *
     * @return 添加提供者的首选项位置，或者如果由于已安装而未添加提供者，则为-1。
     * 
     * @see #getProvider
     * @see #removeProvider
     */
    public static int addProvider(Provider provider) {
	
	return insertProviderAt(provider, providers.size() + 1);
    }

    /**
     * Removes the provider with the specified name.
     *
     * <p>删除指定提供商时，位于比指定提供商所在位置更高的所有提供商都会向下移动一个位置（朝向已安装提供商列表的头部）。
     *
     * <p>This method returns silently if the provider is not installed.
     *
     * @param name the name of the provider to remove.
     *
     * @see #getProvider
     * @see #addProvider
     */
    public static void removeProvider(String name) {

	check();
	
	Provider provider = getProvider(name);

	if (provider != null) {
	    providers.removeElement(provider);
	}
    }

    
    /**
     * Returns all providers currently installed.
     * 
     * @return an array of all providers currently installed.
     */
    public static Provider[] getProviders() {
	check();
	Provider[] result = new Provider[providers.size()];
	providers.copyInto(result);
	return result;
    }

    /**
     * 返回以指定名称安装的提供程序（如果有的话）。如果未安装具有指定名称的提供程序，则返回空。
     * 
     * @param name the name of the provider to get.
     * 
     * @return the provider of the specified name.
     *
     * @see #removeProvider
     * @see #addProvider
     */
    public static Provider getProvider(String name) {
	check();
	Enumeration enum = providers.elements();
	while (enum.hasMoreElements()) {
	    Provider prov = (Provider)enum.nextElement();
	    if (prov.getName().equals(name)) {
		return prov;
	    }
	}
	return null;
    }

    private static boolean checkSuperclass(Class subclass, Class superclass) {
	while(!subclass.equals(superclass)) {
	    subclass = subclass.getSuperclass();
	    if (subclass == null) {
		return false;
	    }
	}
	return true;
    }

    /*
     * 返回配置为实现类型的对象。提供者可以为空，在这种情况下，将按首选项顺序搜索所有提供者。
     */
    static Object getImpl(String algorithm, String type, String provider)
    throws NoSuchAlgorithmException, NoSuchProviderException {	

	String className = getEngineClassName(algorithm, provider, type);

	try {
	    Class typeClass = Class.forName("java.security." + type);
	    Class cl = Class.forName(className);

	    if (checkSuperclass(cl, typeClass)) {
		return cl.newInstance();
	    } else {
		throw new NoSuchAlgorithmException("class configured for " + 
						   type + ": " + className + 
						   " not a " + type);
	    }
	} catch (ClassNotFoundException e) {
	    throw new NoSuchAlgorithmException("class configured for " + 
					       type + "(provider: " + 
					       provider + ")" + 
					       "cannot be found.\n" + 
					       e.getMessage());
	} catch (InstantiationException e) {
	    throw new NoSuchAlgorithmException("class " + className + 
					       " configured for " + type +
					       "(provider: " + provider + 
					       ") cannot be instantiated.\n" + 
					       e.getMessage());
	} catch (IllegalAccessException e) {
	    throw new NoSuchAlgorithmException("class " + className + 
					       " configured for " + type +
					       "(provider: " + provider +
					       ") cannot be accessed.\n" + 
					       e.getMessage());
	}
    }

    /**
     * Gets a security property.
     *
     * @param key the key of the property being retrieved.
     *
     * @return the valeu of the security property corresponding to key.
     */
    public static String getProperty(String key) {
	check();
	return props.getProperty(key);
    }

    /**
     * Sets a security property.
     *
     * @param key the name of the property to be set.
     *
     * @param datum the value of the property to be set.
     */
    public static void setProperty(String key, String datum) {
	check();
	props.put(key, datum);
    }

    private static void check() {
	
	SecurityManager security = System.getSecurityManager();
	if (security != null) {
	    security.checkSecurityAccess("java");
	}
    }
    
    /**
     * Print an error message that may be significant to a user.
     */
    static void error(String msg) {
	if (debug) {
	    System.err.println(msg);
	}
    }

    /**
     * Print an error message that may be significant to a user.
     */
    static void error(String msg, Throwable t) {
	error(msg);
	if (debug) {
	    t.printStackTrace();
	}
    }
	
    /**
     * Print an debugging message that may be significant to a developer.
     */
    static void debug(String msg) {
	if (debug) {
	    System.err.println(msg);
	}
    }

    /**
     * Print an debugging message that may be significant to a developer.
     */
    static void debug(String msg, Throwable t) {
	if (debug) {
	    t.printStackTrace();
	    System.err.println(msg);
	}
    }

    
	
}
	

